/**
 * @fileoverview
 * Queue with local storage and data packet (buffer) processing
 * 
 * @author Sebastian Brzuzek sebastian@brzuzek.pl
 */

goog.provide('uxperf.Queue');
goog.provide('uxperf.Queue.EVENT_TYPES');

goog.require('uxperf.Config');
goog.require('uxperf.FactoryBase.Autoinit');
goog.require('goog.events.EventTarget');
goog.require('goog.array');

/**
 * Class for FIFO Queue data structure with given storage.
 * Data will be delivered in packets called buffers
 * 
 * @constructor
 * @extends {goog.events.EventTarget}
 * @implements {uxperf.FactoryBase.Autoinit}
 */
uxperf.Queue = function() {
	goog.base(this);

  /**
   * @type {Object}
   */
 	var tmp = {};
	tmp[uxperf.Queue.CONFIG.KEY] = uxperf.Queue.DEFAULT_CONFIG || {};
	uxperf.Config.setDefaults(tmp);

	/**
	 * flag if queue is ready to accept items
	 * @type {boolean}
	 */
	this.ready_ = false;
	
	/**
	 * state of processing
	 * @type {number}
	 */
	this.busy_ = 0;
	
	/**
	 * flag if queue is in flush mode
	 * @type {boolean}
	 */
	this.flushMode_ = false;
	
	/**
	 * storage instance assigned to queue
	 * @type {uxperf.Storage}
	 */
	this.storage_ = uxperf.Storage.getInstance();
	
	/**
	 * counter of processing events used for automatic flush execution
	 * @type {number}
	 */
	this.flushEveryCount_ = 0;
	
	/**
	 * processed buffers count
	 * @type {number}
	 */
	this.processedCount_ = 0;
	
	/**
	 * number part of id of last processed item
	 * @type {number}
	 */
	this.lastProcessedId_ = 0;
	
	/**
	 * number part of id of last queued item
	 * @type {number}
	 */
	this.lastQueuedId_ = 0;

	/**
	 * @type {number}
	 */
  this.itemCount_ = 10;
	
	/**
	 * @type {number}
	 */
	this.cleanupInterval_ = -1;

	/**
	 * @type {number}
	 */
	this.processInterval_ = -1;

	/**
	 * @type {boolean}
	 */
	this.flushOnUnload_ = false;
	
	/**
	 * @type {number}
	 */
	this.flushEvery_ = 1;
	
	/**
	 * @type {number}
	 */
	this.flushItemCount_ = 10;
	
	/**
	 * @type {number}
	 */
	this.busyTop_ = 50;
	
	/**
	 * @type {string}
	 */
	this.bufferPrefix_ = '';
	
	/**
	 * @type {string}
	 */
	this.storageProcessedCountKey_ = '';
	
	/**
	 * @type {string}
	 */
	this.storageProcessedLastKey_ = '';
	
	/**
	 * @type {string}
	 */
	this.storageQueuedLastKey_ = '';
  
  /**
   * @type {number}
   */
  this.infiniteLoopCnt_ = 0;

  /**
   * @type {number}
   */
  this.infiniteLoopLimit_ = 10;
  
  /**
   * @type {number}
   */
  this.queuedHardLimit_ = 300;
  
  /**
   * @type {number}
   */
  this.lastProcessedIdOld_ = -1;
  
  if (goog.DEBUG) LOG.info('Queue construction done');
};
goog.inherits(uxperf.Queue, goog.events.EventTarget);
goog.addSingletonGetter(uxperf.Queue);

/**
 * initialization of queue
 */
uxperf.Queue.prototype.init = function() {
  if (goog.DEBUG) LOG.info('Queue - initialization');
	if (this.ready_) return this;

  //read params

  this.itemCount_ = /** @type {number} */ uxperf.Queue.getParam(uxperf.Queue.CONFIG.ITEM_COUNT);
  this.cleanupInterval_ = /** @type {number} */ uxperf.Queue.getParam(uxperf.Queue.CONFIG.CLEANUP_INTERVAL);
  this.processInterval_ = /** @type {number} */ uxperf.Queue.getParam(uxperf.Queue.CONFIG.PROCESS_INTERVAL);
  this.flushOnUnload_ = /** @type {boolean} */ uxperf.Queue.getParam(uxperf.Queue.CONFIG.FLUSH_ON_UNLOAD);
  this.flushEvery_ = /** @type {number} */ uxperf.Queue.getParam(uxperf.Queue.CONFIG.FLUSH_EVERY);
	this.flushItemCount_ = /** @type {number} */ uxperf.Queue.getParam(uxperf.Queue.CONFIG.FLUSH_ITEM_COUNT);
	if (!this.flushItemCount_ || (this.flushItemCount_ < this.itemCount_)) this.flushItemCount_ = this.itemCount_;
  this.busyTop_ = /** @type {number} */ uxperf.Queue.getParam(uxperf.Queue.CONFIG.BUSY_TOP);
  this.bufferPrefix_ = /** @type {string} */ uxperf.Queue.getParam(uxperf.Queue.CONFIG.BUF_ID_PREFIX);
  this.storageProcessedCountKey_ = /** @type {string} */ uxperf.Queue.getParam(uxperf.Queue.CONFIG.STORAGE_PROCESSED_COUNT);
  this.storageProcessedLastKey_ = /** @type {string} */ uxperf.Queue.getParam(uxperf.Queue.CONFIG.STORAGE_PROCESSED_LAST);
  this.storageQueuedLastKey_ = /** @type {string} */ uxperf.Queue.getParam(uxperf.Queue.CONFIG.STORAGE_QUEUED_LAST);
  this.infiniteLoopLimit_ = /** @type {number} */  uxperf.Queue.getParam(uxperf.Queue.CONFIG.INFINITE_LOOP_LIMIT);
  this.queuedHardLimit_ = /** @type {number} */  uxperf.Queue.getParam(uxperf.Queue.CONFIG.QUEUED_HARD_LIMIT);
  
  //initialize processing counters
	
	this.processedCount_ = /** @type {number} */ this.storage_.get(this.storageProcessedCountKey_) || 0;
	this.lastProcessedId_ = /** @type {number} */ this.storage_.get(this.storageProcessedLastKey_) || 0;
	this.lastQueuedId_ = /** @type {number} */ this.storage_.get(this.storageQueuedLastKey_) || 0;
	  
  //setup listening for processing events
 	goog.events.listen(this, uxperf.Queue.EVENT_TYPES.PROCESS, this);
 	goog.events.listen(this, uxperf.Queue.EVENT_TYPES.FLUSH, this);
 	goog.events.listen(this, uxperf.Queue.EVENT_TYPES.CLEANUP, this);
  
  var queue = this;

  //start cleanup trigger
  if (this.cleanupInterval_ && (this.cleanupInterval_ > 0))
    this.cleanupIntervalId_ = window.setInterval(function () {
        if (goog.DEBUG) LOG.info('Queue - cleanup interval invoked');
        queue.dispatchEvent(uxperf.Queue.EVENT_TYPES.CLEANUP);
      },
      this.cleanupInterval_
    );

  //start processing trigger
  if (this.processInterval_ && (this.processInterval_ > 0))
    this.processIntervalId_ = window.setInterval(function () { 
        if (goog.DEBUG) LOG.info('Queue - process interval invoked');
        queue.dispatchEvent(uxperf.Queue.EVENT_TYPES.PROCESS);
      },
      this.processInterval_
    );
  
  if (this.flushOnUnload_)
   	goog.events.listen(document, goog.events.EventType.UNLOAD, this, true, this);
	
	//report initialization done
	this.readyNotify();
	
	return this;
};

/**
 * base implementation of listener
 *
 * @param {goog.events.Event|Object} e Event to handle
 */
uxperf.Queue.prototype.handleEvent = function(e) {
  if (goog.DEBUG) LOG.info('Queue handle event: ' + e.type);
	if (!this.ready_) {
		this.errorNotify('Queue not ready');
		return;
	}
  switch (e.type) {
    case goog.events.EventType.UNLOAD:
      //unload is only for flushOnUnload case
    case uxperf.Queue.EVENT_TYPES.FLUSH:
      this.flushMode_ = true;
    case uxperf.Queue.EVENT_TYPES.PROCESS:
      this.process();
      break;
    case uxperf.Queue.EVENT_TYPES.CLEANUP:
      this.cleanup();
      break;
    case uxperf.Queue.EVENT_TYPES.SAVE:
			var ev = /** @type {uxperf.BufferItemEvent} */ e;
			if (ev.item) {
				this.save(ev);
			} else {
				this.errorNotify('queue received save event with incorrect event object structure');
			}
      break;
    case uxperf.Queue.EVENT_TYPES.SENT:
			var ev = /** @type {uxperf.BufferEvent} */ e;
			if (ev.buffer) {
	      this.sent(ev);
			} else {
				this.errorNotify('queue received sent notification with incorrect event object structure');
			}
      break;
    default:
      this.errorNotify('unknown event delivered: ' + e.type);
  }
};

/**
 * Process queued items
 * @private
 */
uxperf.Queue.prototype.process = function() {
  if (goog.DEBUG) LOG.info('Queue process');
	//check if queue is busy
  if (this.busy_>0) {
    //is automatic queue unlocking enabled
    if (this.busyTop_ && (this.busyTop_>0)) {
      //should be unlocked
      if (this.busy_ > this.busyTop_) {
        //unlock
        this.busy_ = 0;
      } else {
        //increase busy counter
        this.busy_++
        //stop this execution
        return;
      }
    }
  }
  //set queue busy flag
  this.busy_++;

	//check if automatic flush mode should be started
	if (!this.flushMode_ && this.flushEvery_ && (this.flushEvery_>0)) {
		this.flushEveryCount_++;
		if (this.flushEveryCount_ >= this.flushEvery_) {
      if (goog.DEBUG) LOG.info('Queue - automatic flush mode enabled');
			this.flushMode_ = true;
			this.flushEveryCount_ = 0;
		}
	}
	
  //update ids from storage
	/** @type {uxperf.Queue.QPids} */
	var qp = this.getQPids();  

	this.lastQueuedId_ = qp.lQid;
	this.lastProcessedId_ = qp.lPid;
  
	var itemCount = this.flushMode_ ? this.flushItemCount_ : this.itemCount_;
  
  if (goog.DEBUG) LOG.info('Queue - number of items collected: ' + (this.lastQueuedId_ - this.lastProcessedId_) );

  //verify if there is something to process in queue
  if ((this.lastProcessedId_ >= this.lastQueuedId_)
      || (!this.flushMode_ && (this.lastQueuedId_ - this.lastProcessedId_ < itemCount))) {
    //nothing to process
    //reset flush mode
		this.flushMode_ = false;
    //release lock
    this.busy_ = 0;
    return;
  }

  //initialize new buffer
  var buf = new uxperf.Buffer();
	this.processedCount_ = /** @type {number} */ this.storage_.get(this.storageProcessedCountKey_) || 0;
  buf.setId(this.bufferPrefix_ + this.processedCount_);
  //if (goog.DEBUG) {
  //  LOG.info('Queue - new buffer id = ' + this.bufferPrefix_ + this.processedCount_);
  //  LOG.info('Queue - lastProcessedId = ' + this.lastProcessedId_);
  //  LOG.info('Queue - lastQueuedId = ' + this.lastQueuedId_);
  //}
  
  //add items
  var realCnt = 0;
  var anyCnt = 0;
	for (var i = 0; (i < itemCount) && (this.lastProcessedId_ + i <= this.lastQueuedId_); i++) {
		var item = this.storage_.get(/** @type {string} */ (this.lastProcessedId_ + i));
    //if (goog.DEBUG) LOG.info('Queue - add item [' + (this.lastProcessedId_ + i) + ']: ' + item);
    if (item) {
      realCnt++;
      if (item) buf.push(item);
    }
    anyCnt++;
	}
  if (realCnt<=0) {
  	//update last processed item id
    this.lastProcessedId_ = this.lastProcessedId_ + anyCnt;
  	this.storage_.set(this.storageProcessedLastKey_, /** @type {string} */ (this.lastProcessedId_));
    //unlock processing
    this.busy_ = 0;
    return;
  }
  //send
  if (goog.DEBUG) LOG.info('Queue - send buf: ' + (buf.toString()));
  this.send(buf);
  if (goog.DEBUG) LOG.info('Queue - after send');
};

/**
 * Finalize processing of buffer
 * 
 * @param {uxperf.BufferEvent} e
 * @private
 */
uxperf.Queue.prototype.sent = function(e) {
  if (goog.DEBUG) LOG.info('Queue - sent');
	//if queue is not busy we shouldn't accept sent confirmation
	//(event if there was timeout and late notification of success
	//it will be better to repeat sending than to corrupt queue
	//processing counters)
  if (!this.busy_ || (this.busy_ <= 0)) return;
	
  if (goog.DEBUG) LOG.info('Queue - sent - e.buffer: ' + window.JSON.stringify(e.buffer));
	var items = e.buffer.getItems();
  if (goog.DEBUG) LOG.info('Queue - sent - items: ' + window.JSON.stringify(items));
	var cnt = items.length;
  if (goog.DEBUG) LOG.info('Queue - sent - items length: ' + cnt);
	for (var i = 0; i < cnt; i++) {
		var item = items[i];
    if (goog.DEBUG) LOG.info('Queue - sent - item: ' + item);
    var id = goog.isString(item) ? uxperf.BufferItem.idFromString(item) : item.getId();
    if (goog.DEBUG) LOG.info('Queue - sent - item id: ' + id);
		this.storage_.remove(id);
		this.lastProcessedId_ = id;
	}
	//update last processed item id
	this.storage_.set(this.storageProcessedLastKey_, this.lastProcessedId_);
	
	//increase buffer processed count
	this.processedCount_ = /** @type {number} */ this.storage_.get(this.storageProcessedCountKey_) || 0;
  this.processedCount_ = Number(this.processedCount_);
	this.processedCount_++;
	this.storage_.set(this.storageProcessedCountKey_, (/** @type {string} */ this.processedCount_));

  if (goog.DEBUG) LOG.info('Queue - cleanup and update of counters done');

  if (this.lastProcessedId_ == this.lastProcessedIdOld_) {
    this.infiniteLoopCnt_++;
    if (this.infiniteLoopCnt_ > this.infiniteLoopLimit_) throw Error('Infinite loop protection.');
  } else {
    this.infiniteLoopCnt_ = 0;
    this.lastProcessedIdOld_ = this.lastProcessedId_;
  }
  
	//release busy lock
	this.busy_ = 0;
	
	//if we are in flush mode we should process next packed of data
	if (this.flushMode_) this.dispatchEvent(uxperf.Queue.EVENT_TYPES.PROCESS);
};

/**
 * Save item into queue in asynchronous way
 * NB! there is no guaranty that ID is assigned in proper order
 * if you need trace sequence of actions use timestamp instead of id
 * 
 * @param {uxperf.BufferItemEvent} e
 * @private
 */
uxperf.Queue.prototype.save = function(e) {
  if (goog.DEBUG) LOG.info('Queue - save');
  
  var item = e.item;
	var queue = this;
	
	setTimeout(function () {
    if (goog.DEBUG) LOG.info('Queue - deferred save of item');
			//TODO verify if it is reasonable to separate id generation to dedicated class - sequencer (with locking and transaction support)
      
			/** @type {uxperf.Queue.QPids} */
			var qp = queue.getQPids();
			      
      if (qp.lQid - qp.lPid >= queue.queuedHardLimit_) {
        if (goog.DEBUG) LOG.info('Queue is FULL - limit of items exceeded : ' + queue.queuedHardLimit_);
        return;
      }

			//assign item id
			//synchronize {
			/** @type {number} */
			var id = queue.lastQueuedId_ = ((queue.lastQueuedId_ > qp.lQid) ? queue.lastQueuedId_ : qp.lQid) + 1; //pierwszy będzie miał id = 1
			queue.storage_.set(queue.storageQueuedLastKey_, /** @type {string} */ id);
			//}
			item.setId(id);
      if (goog.DEBUG) LOG.info('Queue - assigned item id : ' + id);

			//save in storage
      var str = item.toString();
			queue.storage_.set(id, str);
      if (goog.DEBUG) LOG.info('Queue - item saved in storage : ' + str);
		},
		1
	);
};

/**
 * @typedef {{lQid: number, lPid: number}}
 */
uxperf.Queue.QPids;

/**
 * get last queued and last processed id
 * with saving default values to storage
 * if not found
 *
 * @return {uxperf.Queue.QPids}
 */
uxperf.Queue.prototype.getQPids = function() {
	/** @type {uxperf.Queue.QPids} */
	var res = {lQid: 0, lPid: 0};
	/** @type {string} */
	var lQid = /** @type {string} */ this.storage_.get(this.storageQueuedLastKey_);
	if (!goog.isDefAndNotNull(lQid)) {
		res.lQid = 0;
		this.storage_.set(this.storageQueuedLastKey_, '0');
	} else {
		res.lQid = Number(lQid);
	}
	/** @type {string} */ 
	var lPid = /** @type {string} */ this.storage_.get(this.storageProcessedLastKey_);
	if (!goog.isDefAndNotNull(lPid)) {
		res.lPid = 0;
		this.storage_.set(this.storageProcessedLastKey_, '0');
	} else {
		res.lPid = Number(lPid);
	}
	return res;
};

/**
 * Cleanup of storage
 */
uxperf.Queue.prototype.cleanup = function() {
  if (goog.DEBUG) LOG.info('Queue - cleanup');
	//there is small chance that we will have some holes in item id sequence if id will be generated for several events and some will not be saved
	//thers is even smaller chance that there will be situation where some items will stay in storage and last processed id will be increased to bigger value
	//in this method we will clean items from second case
	//TODO

	/** @type {uxperf.Queue.QPids} */
	var qp = this.getQPids();  

  //hard limit total number of queued info - total clear of queue if exceeded
  if (qp.lQid - qp.lPid >= this.queuedHardLimit_) {
    if (goog.DEBUG) LOG.info('Queue - cleanup - Total number of queued items exceeded : ' + this.queuedHardLimit_);
    this.storage_.clear();
    qp = this.getQPids();
    this.lastQueuedId_ = qp.lQid;
    this.lastProcessedId_ = qp.lPid;
    if (goog.DEBUG) LOG.info('Queue - cleanup - Queue is empty.')
    return;
  }
/*
this.storage_.get(key)
this.storage_.set(key,value) //string, string
this.storage_.remove(key)
this.storage_.getCount(key)
this.storage_.clear()
*/

};

/**
 * Removes all registered listeners and disposes event target
 * @override
 * @protected
 */
uxperf.Queue.prototype.disposeInternal = function() {
  
  window.clearInterval(this.cleanupIntervalId_);
  this.cleanupIntervalId_ = null;
  
 	goog.events.unlisten(this, uxperf.Queue.EVENT_TYPES.PROCESS, this);
 	goog.events.unlisten(this, uxperf.Queue.EVENT_TYPES.FLUSH, this);
 	goog.events.unlisten(this, uxperf.Queue.EVENT_TYPES.CLEANUP, this);
	
  if (this.flushOnUnload_)
   	goog.events.unlisten(document, goog.events.EventType.UNLOAD, this);
	
  uxperf.Queue.superClass_.disposeInternal.call(this);
};

/**
 * return true if queue is ready to accept data
 * @return {boolean}
 */
uxperf.Queue.prototype.isReady = function() { return this.ready_; };

/**
 * Notify target about sending of data packet
 * @return {boolean} If anyone called preventDefault on the event object (or
 *     if any of the handlers returns false this will also return false.
 */
uxperf.Queue.prototype.send = function(buffer) {
  if (goog.DEBUG) LOG.info('Queue - send');
	if (!this.ready_) return false;
	return this.dispatchEvent(new uxperf.BufferEvent(uxperf.Queue.EVENT_TYPES.SEND, buffer));
};

/**
 * Notify about successful sent of data packet
 * @return {boolean} If anyone called preventDefault on the event object (or
 *     if any of the handlers returns false this will also return false.
 */
uxperf.Queue.prototype.readyNotify = function() {
  if (goog.DEBUG) LOG.info('Queue - ready notify');
	if (this.ready_) return true;
	this.ready_ = (this.dispatchEvent(uxperf.Queue.EVENT_TYPES.READY)!==false);
	return this.ready_;
};

/**
 * Info about last error
 *
 * @type {Object|string|null}
 */
uxperf.Queue.prototype.lastErrorInfo_ = null;

/**
 * return information about last error
 * 
 * @return {Object|string|null}
 */
uxperf.Queue.prototype.getLastErrorInfo = function() {
	return this.lastErrorInfo_;
};

/**
 * Notify about error
 * 
 * @param {Object|string} errorInfo information about error reason
 * @param {boolean=} opt_withthrow flag if Error should be thrown after notification
 * @return {boolean} If anyone called preventDefault on the event object (or
 *     if any of the handlers returns false this will also return false.
 * @throws {Error}
 */
uxperf.Queue.prototype.errorNotify = function(errorInfo, opt_withthrow) {
	this.lastErrorInfo_ = errorInfo;
  var errMsg = uxperf.utils.errorInfoToMsg(errorInfo);
  if (goog.DEBUG) LOG.info('Queue - error notify: ' + errMsg);
	var res = this.dispatchEvent(uxperf.Queue.EVENT_TYPES.ERROR);
	if (goog.DEBUG || opt_withthrow) throw Error(errMsg);
	return res;
};

/**
 * Returns queue parameter value from current configuration
 *
 * @param {...(string|number|!Array.<number|string>)} var_args A number of keys
 *     (as strings, or nubmers, for array-like objects) to retrieve specific value
 *     from configuration structure. Can also be specified as a single array of keys.
 * @return {*} The resulting value. If, at any point, the value for a key
 *     is undefined, returns undefined.
 */
uxperf.Queue.getParam = function(var_args) {
	return uxperf.Config.getSub(uxperf.Queue.CONFIG.KEY, goog.array.toArray(arguments));
};

/**
 * constants related to configuration structure
 * @enum {string}
 */
uxperf.Queue.CONFIG = {
	KEY : 'queue',
	ITEM_COUNT : 'item_count', //item count in buffer
  CLEANUP_INTERVAL : 'cleanup_interval', //in seconds, use 0/null/false to disable automatic cleanup
  PROCESS_INTERVAL : 'process_interval', //in seconds > 0, use 0/null/false to disable automatic queue processing
  FLUSH_ON_UNLOAD : 'flush_on_unload', //if flush should be executed on unload (for example on logout)
  FLUSH_EVERY : 'flush_every', //number of ticks between flushes - 0/null/false for no automatic flush
	FLUSH_ITEM_COUNT : 'flush_item_count', //maximum item count in buffer when in flush mode (should be greater than general item count to be taken into account)
	BUSY_TOP : 'busy_top', //number of ticks before forced unlock of processing (in case of locking on target), use 0/null/false to disable automatic unlock
  BUF_ID_PREFIX : 'buffer_id_prefix', //prefix used in generation of buffer id
  INFINITE_LOOP_LIMIT : 'infinite_loop_limit', //limit of processing executions without progress on processed id
  QUEUED_HARD_LIMIT : 'queued_hard_limit', //hard limit of queued items if exceeded queue will be emptied
  
	//storage name should be short to reduce space which is important in some cases ex. in cookie
	STORAGE_PROCESSED_COUNT : 'storage_processed_count',
	STORAGE_PROCESSED_LAST : 'storage_processed_last',
	STORAGE_QUEUED_LAST : 'storage_queued_last'
};

/**
 * Default configuration
 * @type {!Object}
 */
uxperf.Queue.DEFAULT_CONFIG = {};
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.ITEM_COUNT] = 10;
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.CLEANUP_INTERVAL] = 120000; //120s
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.PROCESS_INTERVAL] = 15000; //15s
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.FLUSH_ON_UNLOAD] = true;
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.FLUSH_EVERY] = 1;
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.FLUSH_ITEM_COUNT] = 20;
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.BUSY_TOP] = 10;
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.BUF_ID_PREFIX] = 'bufid';
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.INFINITE_LOOP_LIMIT] = 5;
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.QUEUED_HARD_LIMIT] = 300;

uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.STORAGE_PROCESSED_COUNT] = 'pcnt';
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.STORAGE_PROCESSED_LAST] = 'pid';
uxperf.Queue.DEFAULT_CONFIG[uxperf.Queue.CONFIG.STORAGE_QUEUED_LAST] = 'qid';

/**
 * event types related to queue
 * @enum {string}
 */
uxperf.Queue.EVENT_TYPES = {
	READY : 'ready', //ready status notification //TODO verify if we can reuse this value in FactoryBase
	ERROR : 'error', //error notification
	SAVE : 'save', //save buffer item from sensor
	SEND : 'send', //send buffer to target
	SENT : 'sent', //buffer sent confirmation from target
	PROCESS : 'process', //execute standard process queue
	FLUSH : 'flush', //execute flush of queue
	CLEANUP : 'cleanup' //execute garbage collection
};
